#include "board.h"


#include <string>


#include <esp_log.h>
#include <esp_err.h>
#include <driver/gpio.h>
#include <cJSON.h>

#include <ssid_manager.h>
#include <wifi_configuration_ap.h>
#include <wifi_station.h>

#include "config.h"
#include "HTTPClient.h"
#include "system_info.h"
#include "app.h"
#include "HttpsOTA.h"
#include "logger_app.h"

#define TAG "Board"

Board::Board() {
    ESP_LOGI(TAG, "Board初始化");
}

Board::~Board() {
    ESP_LOGI(TAG, "Board销毁");
}
esp_err_t Board::Start() {
    auto& app = App::GetInstance();
    app.SetDeviceState(kDeviceStateHardwareInit);
    esp_err_t ret = ESP_OK;
    ret = InitializeWS2812(23, 1);
    ret = InitializeI2C(I2C_NUM_0, GPIO_NUM_22, GPIO_NUM_21);
    ret = InitializePCF8574();
    ret = InitializeDipSwitch();  // 初始化拨码开关
    if (ret != ESP_OK) {
        ESP_LOGE(TAG, "硬件初始化失败: %s", esp_err_to_name(ret));
        app.SetDeviceState(kDeviceStateHardwareError);
        return ret;
    }
    ESP_LOGI(TAG, "硬件初始化完成，设备编号: 0x%02X", ReadDipSwitch());
    app.SetDeviceState(kDeviceStateHardwareOk);

    return ESP_OK;
}

void Board::WifiConfig() {
    ESP_LOGI(TAG, "开始WiFi配网");
    App::GetInstance().SetDeviceState(kDeviceStateWifiConfig);
    // 启动WiFi配置AP
    auto& wifi_ap = WifiConfigurationAp::GetInstance();
    char ssid_prefix[32];
    sprintf(ssid_prefix,WIFI_AP_SSID_PREFIX"%s",SystemInfo::GetMacAddress().c_str());
    wifi_ap.SetSsidPrefix(ssid_prefix);
    wifi_ap.Start();
}

esp_err_t Board::StartNetwork() {
    auto& app = App::GetInstance();
    app.SetDeviceState(kDeviceStateConnecting);

   if (ReadDipSwitch() == 0x0E)
   {
      ESP_LOGI(TAG, "配置模式，进入配网");
      WifiConfig();
      return ESP_FAIL;
   }
    //检查是否有已配置的WiFi SSID
    auto& ssid_list = SsidManager::GetInstance().GetSsidList();
    if (ssid_list.empty()) {
        ESP_LOGI(TAG, "添加默认WiFi配置");
        SsidManager::GetInstance().AddSsid(WIFI_SSID,WIFI_PASSWD);
        //不需要配网，想要进配网可以直接设置拨码开关为0x0E
    }
    
    // 记录已配置的SSID列表到LoggerApp
    std::vector<std::string> configured_ssids;
    for (const auto& ssid_info : ssid_list) {
        configured_ssids.push_back(ssid_info.ssid);
    }
    LoggerApp::GetInstance().RecordConfiguredSsids(configured_ssids);

    // // 连接WiFi网络
    auto& wifi_station = WifiStation::GetInstance();
    wifi_station.OnScanBegin([]() {
        ESP_LOGI("TAG", "正在扫描WiFi网络...");
    });
    wifi_station.OnScanDown([](uint16_t ap_num, wifi_ap_record_t* ap_records) {
        ESP_LOGI(TAG, "扫描到%d个WiFi网络", ap_num);
        if (ap_num == 0) {
              ESP_LOGI(TAG, "Nothing AP found");
              return;
        }//如果apCount没有受到数据，则说明没有路由器
        
        // 准备WiFi扫描结果数据
        std::vector<WifiScanResult> scan_results;
        
        int i;
        for (i=0; i<ap_num; i++) {
            char *authmode;
            switch(ap_records[i].authmode) {
            case WIFI_AUTH_OPEN:
                authmode = "OPEN";
                break;
            case WIFI_AUTH_WEP:
                authmode = "WEP";
                break;           
            case WIFI_AUTH_WPA_PSK:
                authmode = "WPA";
                break;           
            case WIFI_AUTH_WPA2_PSK:
                authmode = "WPA2";
                break;           
            case WIFI_AUTH_WPA_WPA2_PSK:
                authmode = "WPA/WPA2";
                break;
            default:
                authmode = "Unknown";
                break;
            }
            ESP_LOGI(TAG, "SSID: %s, RSSI: %d, AUTH: %s", ap_records[i].ssid, ap_records[i].rssi, authmode);
            
            // 添加到扫描结果
            WifiScanResult result;
            result.ssid = std::string(reinterpret_cast<const char*>(ap_records[i].ssid));
            result.rssi = ap_records[i].rssi;
            result.auth_mode = std::string(authmode);
            scan_results.push_back(result);
        }
        
        // 记录WiFi扫描结果到LoggerApp
        LoggerApp::GetInstance().RecordWifiScanResults(scan_results);
    });
    wifi_station.OnConnect([](const std::string& ssid) {
        ESP_LOGI("TAG", "正在连接到WiFi...");
    });
    wifi_station.OnConnected([this](const std::string& ssid) {
        ESP_LOGI("TAG", "WiFi连接成功");
        App::GetInstance().SetDeviceState(kDeviceStateNetworkOk);
        StartOta();//获得了IP，尝试OTA
    });
    wifi_station.OnDisconnect([]() {
        ESP_LOGE(TAG, "WiFi连接失败");
        App::GetInstance().SetDeviceState(kDeviceStateNetworkError);
    });
    wifi_station.Start();

    if (!wifi_station.WaitForConnected(WIFI_TIMEOUT)) {
      wifi_station.Stop();
      ESP_LOGW(TAG, "连接WiFi超时: %s", ssid_list[0].ssid.c_str());
      app.SetDeviceState(kDeviceStateNetworkError);
      WifiConfig();
      return ESP_FAIL;
    } 

    ESP_LOGI(TAG, "网络连接成功");
    app.SetDeviceState(kDeviceStateNetworkOk);
    return ESP_OK;
}
// 简化的版本比较函数
bool compareVersionAdvanced(const std::string& download_url, const std::string& current_version) {
    // 从URL中提取文件名
    size_t slash_pos = download_url.find_last_of('/');
    if (slash_pos == std::string::npos) {
        ESP_LOGE(TAG, "无效的URL格式");
        return false;
    }
    
    std::string filename = download_url.substr(slash_pos + 1);
    
    // 移除.bin扩展名
    size_t dot_pos = filename.find(".bin");
    if (dot_pos == std::string::npos) {
        ESP_LOGE(TAG, "文件名格式不正确，应为*.bin");
        return false;
    }
    
    std::string remote_version = filename.substr(0, dot_pos);
    
    // 验证版本号格式（6位数字）
    if (remote_version.length() != 6) {
        ESP_LOGE(TAG, "版本号格式错误，应为6位数字(YYMMDD)");
        return false;
    }
    
    // 简单的数字验证和转换
    for (char c : remote_version) {
        if (c < '0' || c > '9') {
            ESP_LOGE(TAG, "版本号包含非数字字符");
            return false;
        }
    }
    
    // 直接字符串比较（YYMMDD格式下有效）
    int remote_int = atoi(remote_version.c_str());
    int current_int = atoi(current_version.c_str());
    
    ESP_LOGI(TAG, "版本比较: 远程=%s, 当前=%s", remote_version.c_str(), current_version.c_str());
    
    return remote_int > current_int;
}

void Board::StartOta() {
    // 使用原子exchange操作，如果返回true说明已经在进行中
    if (ota_in_progress_.exchange(true)) {
        ESP_LOGI(TAG, "OTA正在进行中，跳过");
        return;
    }
    
    // 检查是否已完成
    if (ota_completed_.load()) {
        ESP_LOGI(TAG, "OTA已完成，跳过");
        ota_in_progress_.store(false); // 恢复状态
        return;
    }
    
    ESP_LOGI(TAG, "开始OTA检查");
    

    App::GetInstance().SetDeviceState(kDeviceStateOta);
    auto& wifi_station = WifiStation::GetInstance();
    if (!wifi_station.IsConnected()) {
        ESP_LOGW(TAG, "WiFi未连接，无法进行OTA");
        App::GetInstance().SetDeviceState(kDeviceStateOtaError);
        ota_in_progress_.store(false);  // 清除进行中标志
        return;
    }
    std::string HTTP_URL=OTA_URL+SystemInfo::GetMacAddress()+"&version="+VERSION;
    http_client.get(HTTP_URL,[this](const HttpResponse& response){
        auto& app = App::GetInstance();
        if (response.statusCode == 200) {
            // 解析JSON响应
            cJSON* json = cJSON_Parse(response.body.c_str());
            if (json == nullptr) {
                ESP_LOGE(TAG, "JSON解析失败");
                app.SetDeviceState(kDeviceStateOtaError);
                ota_in_progress_.store(false);  // 清除进行中标志
                return;
            }
            
            // 获取code字段
            cJSON* code_item = cJSON_GetObjectItem(json, "code");
            if (!cJSON_IsNumber(code_item)) {
                ESP_LOGE(TAG, "JSON中缺少code字段或类型错误");
                cJSON_Delete(json);
                app.SetDeviceState(kDeviceStateOtaError);
                ota_in_progress_.store(false);  // 清除进行中标志
                return;
            }
            int code = code_item->valueint;
            if (code == 100) {
                ESP_LOGI(TAG, "发现新版本，开始OTA更新");
                // 获取url字段
                cJSON* url_item = cJSON_GetObjectItem(json, "url");
                if (!cJSON_IsString(url_item)) {
                    ESP_LOGE(TAG, "JSON中缺少url字段或类型错误");
                    cJSON_Delete(json);
                    app.SetDeviceState(kDeviceStateOtaError);
                    ota_in_progress_.store(false);  // 清除进行中标志
                    return;
                }
                std::string download_url = url_item->valuestring;
                // 版本比较
                if (!compareVersionAdvanced(download_url, VERSION)) {
                    ESP_LOGI(TAG, "无需更新，保持当前版本");
                    cJSON_Delete(json);
                    ota_completed_.store(true);     // 设置完成标志
                    ota_in_progress_.store(false);  // 清除进行中标志
                    return;
                }
                HttpsOTAUpdateClass ota_;
                ota_.onHttpEvent(ota_.HttpEvent);
                ESP_LOGI(TAG, "开始OTA下载");
                App::GetInstance().SetDeviceState(kDeviceStateOtaWrite);
                ota_.begin(download_url.c_str(),true); 
                HttpsOTAStatus_t otastatus;
                while(1){
                    otastatus = ota_.status();
                    if(otastatus == HTTPS_OTA_SUCCESS) { 
                        ESP_LOGI(TAG, "OTA成功，重启设备");
                        ota_completed_.store(true);     // 设置完成标志
                        ota_in_progress_.store(false);  // 清除进行中标志
                        esp_restart();
                    } else if(otastatus == HTTPS_OTA_FAIL) { 
                        ESP_LOGE(TAG, "OTA失败，重启设备");
                        app.SetDeviceState(kDeviceStateOtaError);
                        ota_in_progress_.store(false);  // 清除进行中标志
                        esp_restart();
                    }
                    vTaskDelay(pdMS_TO_TICKS(1000));
                }
            } else{
                ESP_LOGI(TAG, "当前版本已是最新");
                ota_completed_.store(true);     // 设置完成标志
                ota_in_progress_.store(false);  // 清除进行中标志
            }
        }
        else{
            ESP_LOGE(TAG, "获取OTA信息失败: %d", response.statusCode);
            app.SetDeviceState(kDeviceStateOtaError);
            ota_in_progress_.store(false);  // 清除进行中标志
        }
    });
}

esp_err_t Board::InitializeI2C(i2c_port_num_t port, gpio_num_t scl, gpio_num_t sda) {
    if (i2c_) {
        ESP_LOGW(TAG, "I2C已初始化");
        return ESP_FAIL;
    }

    I2CConfig config = {
        .type = I2CType::HARDWARE,
        .i2c_port = port,
        .scl_io_num = scl,
        .sda_io_num = sda,
        .enable_internal_pullup = true,
    };

    i2c_ = std::make_shared<I2cMaster>();
    esp_err_t ret = i2c_->init(config);
    if (ret != ESP_OK) {
        ESP_LOGE(TAG, "I2C初始化失败: %s", esp_err_to_name(ret));
        i2c_.reset();
        return ret;
    }
    ESP_LOGI(TAG, "I2C初始化完成");
    return ESP_OK;
}


esp_err_t Board::InitializePCF8574() {
    if (pcf8574_1_) {
        ESP_LOGW(TAG, "PCF8574已初始化");
        return ESP_FAIL;
    }
 
    pcf8574_1_ = std::make_unique<PCF8574>(i2c_,0x21);
    pcf8574_2_ = std::make_unique<PCF8574>(i2c_,0x20);
    pcf8574_3_ = std::make_unique<PCF8574>(i2c_,0x22);
    for(uint8_t  i=0;i<8;i++) {
        pcf8574_1_->pinMode(i,OUTPUT,LOW);
        pcf8574_2_->pinMode(i,OUTPUT,LOW);
        pcf8574_3_->pinMode(i,OUTPUT,LOW);
    }
    esp_err_t ret = pcf8574_1_->begin();
    if (ret != ESP_OK) {
        ESP_LOGE(TAG, "PCF8574_1初始化失败: %s", esp_err_to_name(ret));
        pcf8574_1_.reset();
        return ret;
    }
    ret = pcf8574_2_->begin();
    if (ret != ESP_OK) {
        ESP_LOGE(TAG, "PCF8574_2初始化失败: %s", esp_err_to_name(ret));
        pcf8574_2_.reset();
        return ret;
    }
    ret = pcf8574_3_->begin();
    if (ret != ESP_OK) {
        ESP_LOGE(TAG, "PCF8574_3初始化失败: %s", esp_err_to_name(ret));
        pcf8574_3_.reset();
        return ret;
    }
    ESP_LOGI(TAG, "PCF8574初始化完成"); 
    return ESP_OK;
}


std::array<PCF8574*, 3> Board::GetPCF8574Array() {
    // 安全检查：确保PCF8574已经初始化
    if (!pcf8574_1_ || !pcf8574_2_ || !pcf8574_3_) {
        ESP_LOGW(TAG, "PCF8574设备未完全初始化");
    }
    
    return {
        pcf8574_1_.get(),
        pcf8574_2_.get(), 
        pcf8574_3_.get()
    };
}

PCF8574* Board::GetPCF8574(size_t index) {
    switch (index) {
        case 0: return pcf8574_1_.get();
        case 1: return pcf8574_2_.get();
        case 2: return pcf8574_3_.get();
        default:
            ESP_LOGW(TAG, "无效的PCF8574索引: %zu", index);
            return nullptr;
    }
}

esp_err_t Board::InitializeWS2812(int gpio_pin, int led_count) {
    if (ws2812_) {
        ESP_LOGW(TAG, "WS2812已初始化");
        return ESP_FAIL;
    }
    
    ws2812_ = std::make_unique<WS2812>(gpio_pin, led_count);
    
    esp_err_t ret = ws2812_->Initialize();
    if (ret != ESP_OK) {
        ESP_LOGE(TAG, "WS2812初始化失败: %s", esp_err_to_name(ret));
        ws2812_.reset();
        return ret;
    }
    ESP_LOGI(TAG, "WS2812初始化完成");
    return ESP_OK;
}

WS2812* Board::GetWS2812() {
    return ws2812_.get();
}

esp_err_t Board::InitializeDipSwitch() {
    gpio_config_t io_conf = {};
    
    // 配置拨码开关GPIO为输入模式，启用内部上拉
    for (int i = 0; i < 5; i++) {
        io_conf.intr_type = GPIO_INTR_DISABLE;      // 禁用中断
        io_conf.mode = GPIO_MODE_INPUT;             // 输入模式
        io_conf.pin_bit_mask = (1ULL << DIP_SWITCH_PINS[i]);
        io_conf.pull_down_en = GPIO_PULLDOWN_DISABLE;   // 禁用下拉
        io_conf.pull_up_en = GPIO_PULLUP_ENABLE;        // 启用上拉
        
        esp_err_t ret = gpio_config(&io_conf);
        if (ret != ESP_OK) {
            ESP_LOGE(TAG, "拨码开关GPIO %d配置失败: %s", DIP_SWITCH_PINS[i], esp_err_to_name(ret));
            return ret;
        }
    }
    
    ESP_LOGI(TAG, "拨码开关初始化完成");
    return ESP_OK;
}

uint8_t Board::ReadDipSwitch() {
    uint8_t value = 0;
    
    // 读取每一位拨码开关的状态
    // 拨码开关闭合时GPIO读取为低电平(0)，断开时为高电平(1)
    // 为了符合常规逻辑，我们将低电平解释为开关闭合(1)，高电平为开关断开(0)
    for (int i = 0; i < 5; i++) {
        int gpio_level = gpio_get_level(DIP_SWITCH_PINS[i]);
        if (gpio_level == 0) {  // GPIO为低电平表示拨码开关闭合
            value |= (0 << i);  // 设置对应位为1
        }
        else{
            value |= (1 << i);  // 设置对应位为1
        }
    }
    
    ESP_LOGI(TAG, "拨码开关值: 0x%02X", value);
    return value;
}
